"""
JWT 认证系统主应用

完整的企业级 JWT 认证实现
"""

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from datetime import timedelta
from typing import List
import sys
from pathlib import Path

# 处理导入路径
if __name__ == "__main__" or "." not in __name__:
    sys.path.insert(0, str(Path(__file__).parent.parent.parent))
    from stage2_advanced.chapter02_jwt import crud, schemas, models
    from stage2_advanced.chapter02_jwt.database import get_db, init_db, engine
    from stage2_advanced.chapter02_jwt.security import (
        verify_password,
        create_access_token,
        create_refresh_token,
        verify_token,
    )
    from stage2_advanced.chapter02_jwt.config import ACCESS_TOKEN_EXPIRE_MINUTES
    from stage2_advanced.chapter02_jwt.dependencies import get_current_user, require_admin
else:
    from . import crud, schemas, models
    from .database import get_db, init_db, engine
    from .security import (
        verify_password,
        create_access_token,
        create_refresh_token,
        verify_token,
    )
    from .config import ACCESS_TOKEN_EXPIRE_MINUTES
    from .dependencies import get_current_user, require_admin


# ========== 创建 FastAPI 应用 ==========

app = FastAPI(
    title="JWT 认证系统",
    description="企业级 JWT 认证实现，包含用户注册、登录、Token 刷新等功能",
    version="1.0.0",
)


# ========== 启动事件 ==========

@app.on_event("startup")
def on_startup():
    """
    应用启动时初始化数据库
    """
    # 创建所有表
    init_db()
    
    # 创建默认管理员用户（如果不存在）
    db = next(get_db())
    admin = crud.get_user_by_username(db, username="admin")
    if not admin:
        crud.create_superuser(
            db,
            username="admin",
            email="admin@example.com",
            password="Admin123",  # 生产环境请修改！
            full_name="系统管理员"
        )
        print("✅ 默认管理员账户已创建：admin / Admin123")
    db.close()


# ========== 认证路由 ==========

@app.post("/auth/register", response_model=schemas.UserResponse, tags=["认证"])
def register(
    user_in: schemas.UserCreate,
    db: Session = Depends(get_db)
):
    """
    用户注册
    
    创建新用户账户
    
    - **username**: 用户名（3-50字符）
    - **email**: 邮箱
    - **password**: 密码（至少8字符，包含大小写字母和数字）
    - **full_name**: 全名（可选）
    """
    # 1. 检查用户名是否已存在
    existing_user = crud.get_user_by_username(db, username=user_in.username)
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Username already registered"
        )
    
    # 2. 检查邮箱是否已存在
    existing_email = crud.get_user_by_email(db, email=user_in.email)
    if existing_email:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already registered"
        )
    
    # 3. 创建用户
    user = crud.create_user(db, user=user_in)
    
    return user


@app.post("/auth/login", response_model=schemas.Token, tags=["认证"])
def login(
    form_data: OAuth2PasswordRequestForm = Depends(),
    db: Session = Depends(get_db)
):
    """
    用户登录
    
    OAuth2 密码流程，返回 Access Token 和 Refresh Token
    
    - **username**: 用户名
    - **password**: 密码
    
    返回：
    - **access_token**: 访问令牌（30分钟有效）
    - **refresh_token**: 刷新令牌（7天有效）
    - **token_type**: Token 类型（bearer）
    """
    # 1. 验证用户名
    user = crud.get_user_by_username(db, username=form_data.username)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 2. 验证密码
    if not verify_password(form_data.password, user.hashed_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 3. 检查用户是否激活
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Inactive user"
        )
    
    # 4. 生成 Token
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username},
        expires_delta=access_token_expires
    )
    
    refresh_token = create_refresh_token(
        data={"sub": user.username}
    )
    
    # 5. 返回 Token
    return {
        "access_token": access_token,
        "refresh_token": refresh_token,
        "token_type": "bearer"
    }


@app.post("/auth/refresh", response_model=schemas.Token, tags=["认证"])
def refresh_token(
    refresh_token: str,
    db: Session = Depends(get_db)
):
    """
    刷新 Access Token
    
    使用 Refresh Token 获取新的 Access Token
    
    - **refresh_token**: 刷新令牌
    
    返回：
    - **access_token**: 新的访问令牌
    - **refresh_token**: 新的刷新令牌
    - **token_type**: Token 类型
    """
    # 1. 验证 Refresh Token
    payload = verify_token(refresh_token)
    if payload is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid refresh token",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 2. 检查 Token 类型
    if payload.get("type") != "refresh":
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token type. Expected refresh token.",
        )
    
    # 3. 提取用户名
    username: str = payload.get("sub")
    if username is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token payload",
        )
    
    # 4. 查询用户
    user = crud.get_user_by_username(db, username=username)
    if user is None or not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User not found or inactive",
        )
    
    # 5. 生成新的 Access Token
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    new_access_token = create_access_token(
        data={"sub": user.username},
        expires_delta=access_token_expires
    )
    
    # 6. 生成新的 Refresh Token（Token 轮换）
    new_refresh_token = create_refresh_token(
        data={"sub": user.username}
    )
    
    return {
        "access_token": new_access_token,
        "refresh_token": new_refresh_token,
        "token_type": "bearer"
    }


# ========== 用户路由 ==========

@app.get("/users/me", response_model=schemas.UserResponse, tags=["用户"])
def read_users_me(
    current_user: models.User = Depends(get_current_user)
):
    """
    获取当前用户信息
    
    返回登录用户的详细信息
    
    需要认证：✅
    """
    return current_user


@app.put("/users/me", response_model=schemas.UserResponse, tags=["用户"])
def update_users_me(
    user_update: schemas.UserUpdate,
    current_user: models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    更新当前用户信息
    
    更新登录用户的邮箱、全名等信息
    
    需要认证：✅
    
    - **email**: 新邮箱（可选）
    - **full_name**: 新全名（可选）
    """
    # 检查邮箱是否被其他用户使用
    if user_update.email:
        existing_user = crud.get_user_by_email(db, email=user_update.email)
        if existing_user and existing_user.id != current_user.id:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Email already in use"
            )
    
    updated_user = crud.update_user(db, user=current_user, user_update=user_update)
    return updated_user


@app.put("/users/me/password", response_model=schemas.MessageResponse, tags=["用户"])
def change_password(
    password_data: schemas.PasswordChange,
    current_user: models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    修改密码
    
    用户修改自己的密码
    
    需要认证：✅
    
    - **old_password**: 旧密码
    - **new_password**: 新密码（至少8字符，包含大小写字母和数字）
    """
    # 1. 验证旧密码
    if not verify_password(password_data.old_password, current_user.hashed_password):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Incorrect password"
        )
    
    # 2. 更新密码
    crud.update_user_password(db, user=current_user, new_password=password_data.new_password)
    
    return {"message": "Password updated successfully"}


# ========== 管理员路由 ==========

@app.get("/users", response_model=List[schemas.UserResponse], tags=["管理员"])
def read_users(
    skip: int = 0,
    limit: int = 100,
    current_user: models.User = Depends(require_admin),
    db: Session = Depends(get_db)
):
    """
    获取用户列表
    
    管理员获取所有用户列表
    
    需要认证：✅（管理员）
    
    - **skip**: 跳过的记录数（分页）
    - **limit**: 返回的最大记录数
    """
    users = crud.get_users(db, skip=skip, limit=limit)
    return users


@app.get("/users/{user_id}", response_model=schemas.UserResponse, tags=["管理员"])
def read_user(
    user_id: int,
    current_user: models.User = Depends(require_admin),
    db: Session = Depends(get_db)
):
    """
    获取用户详情
    
    管理员根据 ID 获取用户详细信息
    
    需要认证：✅（管理员）
    
    - **user_id**: 用户 ID
    """
    user = crud.get_user(db, user_id=user_id)
    if user is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    return user


@app.delete("/users/{user_id}", response_model=schemas.MessageResponse, tags=["管理员"])
def delete_user(
    user_id: int,
    current_user: models.User = Depends(require_admin),
    db: Session = Depends(get_db)
):
    """
    删除用户
    
    管理员删除指定用户
    
    需要认证：✅（管理员）
    
    - **user_id**: 用户 ID
    """
    # 不允许删除自己
    if user_id == current_user.id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Cannot delete yourself"
        )
    
    success = crud.delete_user(db, user_id=user_id)
    if not success:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    return {"message": f"User {user_id} deleted successfully"}


# ========== 根路由 ==========

@app.get("/", tags=["根路径"])
def root():
    """
    API 根路径
    
    返回 API 基本信息
    """
    return {
        "message": "JWT 认证系统 API",
        "version": "1.0.0",
        "docs": "/docs",
        "endpoints": {
            "register": "POST /auth/register",
            "login": "POST /auth/login",
            "refresh": "POST /auth/refresh",
            "me": "GET /users/me",
            "users": "GET /users (管理员)"
        }
    }


# ========== 主程序入口 ==========

if __name__ == "__main__":
    import uvicorn
    
    print("=" * 50)
    print("🚀 启动 JWT 认证系统")
    print("=" * 50)
    print("📖 文档：http://127.0.0.1:8020/docs")
    print("🔐 默认管理员：admin / Admin123")
    print("=" * 50)
    
    uvicorn.run(
        "main:app" if "." not in __name__ else "stage2_advanced.chapter02_jwt.main:app",
        host="0.0.0.0",
        port=8020,
        reload=True
    )


